package com.tsfyun.scm.service.impl.system;

import cn.hutool.core.collection.CollUtil;
import com.google.common.collect.Maps;
import com.tsfyun.common.base.enums.MailContentTypeEnum;
import com.tsfyun.common.base.enums.MailTemplateTypeEnum;
import com.tsfyun.common.base.exception.ServiceException;
import com.tsfyun.common.base.extension.ServiceImpl;
import com.tsfyun.common.base.util.StringUtils;
import com.tsfyun.common.base.validator.ValidatorUtils;
import com.tsfyun.scm.dto.support.SendMailDTO;
import com.tsfyun.scm.entity.system.MailConfig;
import com.tsfyun.scm.entity.system.SendMail;
import com.tsfyun.scm.service.file.IExportFileService;
import com.tsfyun.scm.service.system.IMailConfigService;
import com.tsfyun.scm.service.system.IMailService;
import com.tsfyun.scm.stream.send.ScmProcessor;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;

import java.io.File;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

import static com.tsfyun.scm.util.MailUtil.getInstance;

@Slf4j
@Service
public class MailServiceImpl extends ServiceImpl<SendMail> implements IMailService {

    @Autowired
    private IMailConfigService mailConfigService;

    @Autowired
    private ScmProcessor scmProcessor;

    @Autowired
    private FreeMarkerConfigurer configurer;

    @Autowired
    private IExportFileService exportFileService;

    @Override
    public boolean sendSimple(List<String> receivers, String title, String content, MailContentTypeEnum mailContentTypeEnum) {
        Map<String,Object> checkMap = checkAndInitMailConfigMap(receivers);
        Boolean checkFlag = (Boolean) checkMap.get("result");
        Properties properties = (Properties) checkMap.get("mailInfo");
        if(!checkFlag) {
            return false;
        }
        boolean sendFlag;
        //异步发送由外部程序控制
        String errMsg = getInstance().sendSimple(receivers, title, content);
        sendFlag = StringUtils.isEmpty(errMsg) ? true : false;
        //记录发送邮件信息，方便后续做处理，如补偿发送等等
        SendMail sendMail = new SendMail();
        sendMail.setTitle(title);
        sendMail.setContent(content);
        sendMail.setFromUserMail(StringUtils.null2EmptyWithTrim(properties.get("mail.user")));
        sendMail.setToUsersMail(receivers.stream().collect(Collectors.joining(",")));
        sendMail.setMailType(mailContentTypeEnum.getCode());
        sendMail.setStatus(sendFlag ? 1 : 2);
        sendMail.setMessage(1 == sendMail.getStatus() ? "发送成功" : errMsg);
        super.saveNonNull(sendMail);
        return sendFlag;
    }

    @Override
    public boolean sendSimpleByTemplate(List<String> receivers, String title, MailContentTypeEnum mailContentTypeEnum, MailTemplateTypeEnum mailTemplateTypeEnum, Map<String, Object> data) {
        Template template;
        try {
            template = configurer.getConfiguration().getTemplate(String.format("mail/%s.ftl",mailTemplateTypeEnum.getCode()));
            String content = FreeMarkerTemplateUtils.processTemplateIntoString(template, data);
            return sendSimple(receivers,title,content,mailContentTypeEnum);
        } catch (Exception e) {
            log.error("freemarker获取模板异常",e);
            throw new ServiceException("填充邮件模板异常");
        }
    }

    @Override
    public void sendSimpleWithMQ(List<String> receivers, String title, String content, MailContentTypeEnum mailContentTypeEnum,List<Long> fileIds,Boolean removeFileFlag) {
        if(CollUtil.isEmpty(receivers)) {
            log.error("收件人为空，不发送");
            return;
        }
        SendMail sendMail = new SendMail();
        sendMail.setTitle(title);
        sendMail.setContent(content);
        sendMail.setFromUserMail("");
        sendMail.setToUsersMail(receivers.stream().collect(Collectors.joining(",")));
        sendMail.setMailType(mailContentTypeEnum.getCode());
        sendMail.setStatus(3);
        sendMail.setMessage("准备发送");
        super.saveNonNull(sendMail);
        log.info("开始准备投递邮件消息到MQ服务器，收件人；【{}】",receivers);
        SendMailDTO sendMailDTO =  new SendMailDTO();
        sendMailDTO.setId(sendMail.getId());
        sendMailDTO.setReceivers(receivers);
        sendMailDTO.setTitle(title);
        sendMailDTO.setContent(content);
        sendMailDTO.setFileIds(fileIds);
        sendMailDTO.setRemoveFileFlag(removeFileFlag);
        scmProcessor.sendMail(sendMailDTO);
        log.info("成功投递邮件消息到MQ服务器，等待消费，收件人；【{}】",receivers);
    }

    @Override
    public void sendSimpleWithMQByTemplate(List<String> receivers, String title, MailContentTypeEnum mailContentTypeEnum, MailTemplateTypeEnum mailTemplateTypeEnum, Map<String, Object> data) {
       sendSimpleWithMQByTemplate(receivers,title,mailContentTypeEnum,mailTemplateTypeEnum,data,null,null);
    }

    @Override
    public void sendSimpleWithMQByTemplate(List<String> receivers, String title, MailContentTypeEnum mailContentTypeEnum, MailTemplateTypeEnum mailTemplateTypeEnum, Map<String, Object> data, List<Long> fileIds,Boolean removeFileFlag) {
        Template template;
        try {
            template = configurer.getConfiguration().getTemplate(String.format("mail/%s.ftl",mailTemplateTypeEnum.getCode()));
            String content = FreeMarkerTemplateUtils.processTemplateIntoString(template, data);
            sendSimpleWithMQ(receivers,title,content,mailContentTypeEnum,fileIds,removeFileFlag);
        } catch (Exception e) {
            log.error("freemarker获取模板异常",e);
            throw new ServiceException("填充邮件模板异常");
        }
    }

    @Override
    public void consumeMailByMQ(SendMailDTO dto) {
        Map<String,Object> checkMap = checkAndInitMailConfigMap(dto.getReceivers());
        Boolean checkFlag = (Boolean) checkMap.get("result");
        Properties properties = (Properties) checkMap.get("mailInfo");
        if(!checkFlag) {
            log.error("检查失败，不发送邮件");
            return;
        }
        boolean sendFlag;
        String errMsg;
        boolean sendWithAttachment = false;
        List<File> attachments = new ArrayList<>();
        //发送
        if(CollUtil.isNotEmpty(dto.getFileIds())) {
            //获取文件附件集合
            dto.getFileIds().stream().forEach(id->{
                File file = exportFileService.findExportFile(id);
                ValidatorUtils.isTrueCall(Objects.nonNull(file) && file.exists(),()->{
                    attachments.add(file);
                });
            });
            sendWithAttachment = CollUtil.isNotEmpty(attachments);
        }
        if(!sendWithAttachment) {
            errMsg = getInstance().sendSimple(dto.getReceivers(), dto.getTitle(), dto.getContent());
        } else {
            errMsg = getInstance().sendAttach(dto.getReceivers(), dto.getTitle(), dto.getContent(),attachments.toArray(new File[attachments.size()]));
        }
        sendFlag = StringUtils.isEmpty(errMsg) ? true : false;
        SendMail sendMail = super.getById(dto.getId());
        if(Objects.nonNull(sendMail)) {
            sendMail.setFromUserMail(properties.getProperty("mail.user"));
            sendMail.setStatus(sendFlag ? 1 : 2);
            sendMail.setMessage(1 == sendMail.getStatus() ? "发送成功" : errMsg);
            super.updateById(sendMail);
        }
        Boolean removeFileFlag = dto.getRemoveFileFlag();
        //删除文件
        if(sendFlag && Objects.equals(removeFileFlag,Boolean.TRUE)) {
            attachments.stream().forEach(file -> {
                ValidatorUtils.isTrueCall(Objects.nonNull(file) && file.exists(),()->{
                    file.delete();
                });
            });
        }

    }

    @Override
    public boolean sendAttach(List<String> receivers, String title, String content, MailContentTypeEnum mailContentTypeEnum, File... attaches) {
        Map<String,Object> checkMap = checkAndInitMailConfigMap(receivers);
        Boolean checkFlag = (Boolean) checkMap.get("result");
        Properties properties = (Properties) checkMap.get("mailInfo");
        if(!checkFlag) {
            return false;
        }
        //记录发送邮件信息，方便后续做处理，如补偿发送等等
        boolean sendFlag;
        //异步发送由外部程序控制
        String errMsg  = getInstance().sendAttach(receivers,title,content,attaches);
        sendFlag = StringUtils.isEmpty(errMsg) ? true : false;
        //记录发送邮件信息，方便后续做处理，如补偿发送等等
        SendMail sendMail = new SendMail();
        sendMail.setTitle(title);
        sendMail.setContent(content);
        sendMail.setFromUserMail(StringUtils.null2EmptyWithTrim(properties.get("mail.user")));
        sendMail.setToUsersMail(receivers.stream().collect(Collectors.joining(",")));
        sendMail.setMailType(mailContentTypeEnum.getCode());
        sendMail.setStatus(sendFlag ? 1 : 2);
        sendMail.setMessage(1 == sendMail.getStatus() ? "发送成功" : errMsg);
        super.saveNonNull(sendMail);
        return sendFlag;
    }

    @Override
    public boolean sendAttachByTemplate(List<String> receivers, String title, MailContentTypeEnum mailContentTypeEnum, MailTemplateTypeEnum mailTemplateTypeEnum, Map<String, Object> data, File... attaches) {
        Template template;
        try {
            template = configurer.getConfiguration().getTemplate(String.format("mail/%s.ftl",mailTemplateTypeEnum.getCode()));
            String content = FreeMarkerTemplateUtils.processTemplateIntoString(template, data);
            return sendAttach(receivers,title,content,mailContentTypeEnum,attaches);
        } catch (Exception e) {
            log.error("freemarker获取模板异常",e);
            throw new ServiceException("填充邮件模板异常");
        }
    }

    public Map<String,Object> checkAndInitMailConfigMap(List<String> receivers) {
        Map<String,Object> checkMap = Maps.newHashMap();
        checkMap.put("result",Boolean.TRUE);
        if(CollUtil.isEmpty(receivers)) {
            log.error("收件人为空，不处理");
            checkMap.put("result",Boolean.FALSE);
            return checkMap;
        }
        List<MailConfig> mailConfigs = mailConfigService.openList();
        if(CollUtil.isEmpty(mailConfigs)) {
            log.error("未配置邮件可用邮箱服务器信息，不处理邮件");
            checkMap.put("result",Boolean.FALSE);
            return checkMap;
        }
        ConcurrentHashMap<String, Properties> mailMap = getInstance().mailMap;
        //首次调用加载
        //默认取第一个邮件服务器信息
        //先取默认再按时间排序取
        mailConfigs = mailConfigs.stream().sorted(Comparator.comparing(MailConfig::getIsDefault).thenComparing(MailConfig::getDateUpdated).reversed()).collect(Collectors.toList());
        Properties properties = new Properties();
        properties.put("mail.host", StringUtils.null2EmptyWithTrim(mailConfigs.get(0).getMailHost()));
        properties.put("mail.user",StringUtils.null2EmptyWithTrim(mailConfigs.get(0).getMailUser()));
        properties.put("mail.password",StringUtils.null2EmptyWithTrim(mailConfigs.get(0).getMailPassword()));
        properties.put("mail.port",StringUtils.null2EmptyWithTrim(mailConfigs.get(0).getMailPort()));
        properties.put("mail.retryTimes",mailConfigs.get(0).getRetryTimes());

        checkMap.put("mailInfo",properties);
        mailMap.put("scm",properties);
        return checkMap;
    }
}
